1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package sun.awt.X11;
27
28 import java.awt.dnd.DnDConstants;
29
30 import java.nio.ByteOrder;
31
32 import java.util.Arrays;
33
34 import sun.misc.Unsafe;
35
36
37
38
39
40
41 class MotifDnDConstants {
42
43 private MotifDnDConstants() {}
44
45
46 private static final Unsafe unsafe = XlibWrapper.unsafe;
47 static final XAtom XA_MOTIF_ATOM_0 = XAtom.get("_MOTIF_ATOM_0");
48 static final XAtom XA_MOTIF_DRAG_WINDOW = XAtom.get("_MOTIF_DRAG_WINDOW");
49 static final XAtom XA_MOTIF_DRAG_TARGETS = XAtom.get("_MOTIF_DRAG_TARGETS");
50 static final XAtom XA_MOTIF_DRAG_INITIATOR_INFO =
51 XAtom.get("_MOTIF_DRAG_INITIATOR_INFO");
52 static final XAtom XA_MOTIF_DRAG_RECEIVER_INFO =
53 XAtom.get("_MOTIF_DRAG_RECEIVER_INFO");
54 static final XAtom XA_MOTIF_DRAG_AND_DROP_MESSAGE =
55 XAtom.get("_MOTIF_DRAG_AND_DROP_MESSAGE");
56 static final XAtom XA_XmTRANSFER_SUCCESS =
57 XAtom.get("XmTRANSFER_SUCCESS");
58 static final XAtom XA_XmTRANSFER_FAILURE =
59 XAtom.get("XmTRANSFER_FAILURE");
60 static final XSelection MotifDnDSelection = new XSelection(XA_MOTIF_ATOM_0);
61
62 public static final byte MOTIF_DND_PROTOCOL_VERSION = 0;
63
64
65 public static final int MOTIF_PREFER_PREREGISTER_STYLE = 2;
66 public static final int MOTIF_PREFER_DYNAMIC_STYLE = 4;
67 public static final int MOTIF_DYNAMIC_STYLE = 5;
68 public static final int MOTIF_PREFER_RECEIVER_STYLE = 6;
69
70
71 public static final int MOTIF_INITIATOR_INFO_SIZE = 8;
72 public static final int MOTIF_RECEIVER_INFO_SIZE = 16;
73
74
75 public static final byte MOTIF_MESSAGE_REASON_MASK = (byte)0x7F;
76 public static final byte MOTIF_MESSAGE_SENDER_MASK = (byte)0x80;
77 public static final byte MOTIF_MESSAGE_FROM_RECEIVER = (byte)0x80;
78 public static final byte MOTIF_MESSAGE_FROM_INITIATOR = (byte)0;
79
80
81 public static final int MOTIF_DND_ACTION_MASK = 0x000F;
82 public static final int MOTIF_DND_ACTION_SHIFT = 0;
83 public static final int MOTIF_DND_STATUS_MASK = 0x00F0;
84 public static final int MOTIF_DND_STATUS_SHIFT = 4;
85 public static final int MOTIF_DND_ACTIONS_MASK = 0x0F00;
86 public static final int MOTIF_DND_ACTIONS_SHIFT = 8;
87
88
89 public static final byte TOP_LEVEL_ENTER = 0;
90 public static final byte TOP_LEVEL_LEAVE = 1;
91 public static final byte DRAG_MOTION = 2;
92 public static final byte DROP_SITE_ENTER = 3;
93 public static final byte DROP_SITE_LEAVE = 4;
94 public static final byte DROP_START = 5;
95 public static final byte DROP_FINISH = 6;
96 public static final byte DRAG_DROP_FINISH = 7;
97 public static final byte OPERATION_CHANGED = 8;
98
99
100 public static final int MOTIF_DND_NOOP = 0;
101 public static final int MOTIF_DND_MOVE = 1 << 0;
102 public static final int MOTIF_DND_COPY = 1 << 1;
103 public static final int MOTIF_DND_LINK = 1 << 2;
104
105
106 public static final byte MOTIF_NO_DROP_SITE = (byte)1;
107 public static final byte MOTIF_INVALID_DROP_SITE = (byte)2;
108 public static final byte MOTIF_VALID_DROP_SITE = (byte)3;
109
110 private static long readMotifWindow() throws XException {
111 long defaultScreenNumber = XlibWrapper.DefaultScreen(XToolkit.getDisplay());
112 long defaultRootWindow =
113 XlibWrapper.RootWindow(XToolkit.getDisplay(), defaultScreenNumber);
114
115 long motifWindow = 0;
116
117 WindowPropertyGetter wpg = new WindowPropertyGetter(defaultRootWindow,
118 XA_MOTIF_DRAG_WINDOW,
119 0, 1,
120 false,
121 XConstants.AnyPropertyType);
122 try {
123 int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
124
125 if (status == XConstants.Success &&
126 wpg.getData() != 0 &&
127 wpg.getActualType() == XAtom.XA_WINDOW &&
128 wpg.getActualFormat() == 32 &&
129 wpg.getNumberOfItems() == 1) {
130 long data = wpg.getData();
131
132 motifWindow = Native.getLong(data);
133 }
134
135 return motifWindow;
136 } finally {
137 wpg.dispose();
138 }
139 }
140
141 private static long createMotifWindow() throws XException {
142 assert XToolkit.isAWTLockHeldByCurrentThread();
143
144 long defaultScreenNumber =
145 XlibWrapper.DefaultScreen(XToolkit.getDisplay());
146 long defaultRootWindow =
147 XlibWrapper.RootWindow(XToolkit.getDisplay(), defaultScreenNumber);
148
149 long motifWindow = 0;
150
151 long displayString = XlibWrapper.XDisplayString(XToolkit.getDisplay());
152
153 if (displayString == 0) {
154 throw new XException("XDisplayString returns NULL");
155 }
156
157 long newDisplay = XlibWrapper.XOpenDisplay(displayString);
158
159 if (newDisplay == 0) {
160 throw new XException("XOpenDisplay returns NULL");
161 }
162
163 XlibWrapper.XGrabServer(newDisplay);
164
165 try {
166 XlibWrapper.XSetCloseDownMode(newDisplay, (int)XConstants.RetainPermanent);
167
168 XSetWindowAttributes xwa = new XSetWindowAttributes();
169
170 try {
171 xwa.set_override_redirect(true);
172 xwa.set_event_mask(XConstants.PropertyChangeMask);
173
174 motifWindow = XlibWrapper.XCreateWindow(newDisplay, defaultRootWindow,
175 -10, -10, 1, 1, 0, 0,
176 XConstants.InputOnly,
177 XConstants.CopyFromParent,
178 (XConstants.CWOverrideRedirect |
179 XConstants.CWEventMask),
180 xwa.pData);
181
182 if (motifWindow == 0) {
183 throw new XException("XCreateWindow returns NULL");
184 }
185
186 XlibWrapper.XMapWindow(newDisplay, motifWindow);
187
188 long data = Native.allocateLongArray(1);
189
190 try {
191 Native.putLong(data, motifWindow);
192
193 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
194 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
195 defaultRootWindow,
196 XA_MOTIF_DRAG_WINDOW.getAtom(),
197 XAtom.XA_WINDOW, 32,
198 XConstants.PropModeReplace,
199 data, 1);
200
201 XToolkit.RESTORE_XERROR_HANDLER();
202
203 if (XToolkit.saved_error != null &&
204 XToolkit.saved_error.get_error_code() != XConstants.Success) {
205 throw new XException("Cannot write motif drag window handle.");
206 }
207
208 return motifWindow;
209 } finally {
210 unsafe.freeMemory(data);
211 }
212 } finally {
213 xwa.dispose();
214 }
215 } finally {
216 XlibWrapper.XUngrabServer(newDisplay);
217 XlibWrapper.XCloseDisplay(newDisplay);
218 }
219 }
220
221 private static long getMotifWindow() throws XException {
222
223
224
225
226
227 long motifWindow = readMotifWindow();
228 if (motifWindow == 0) {
229 motifWindow = createMotifWindow();
230 }
231 return motifWindow;
232 }
233
234 public static final class Swapper {
235
236 private Swapper() {}
237
238 public static short swap(short s) {
239 return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8));
240 }
241 public static int swap(int i) {
242 return ((i & 0xFF000000) >>> 24) | ((i & 0x00FF0000) >>> 8) |
243 ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24);
244 }
245
246 public static short getShort(long data, byte order) {
247 short s = unsafe.getShort(data);
248 if (order != MotifDnDConstants.getByteOrderByte()) {
249 return swap(s);
250 } else {
251 return s;
252 }
253 }
254 public static int getInt(long data, byte order) {
255 int i = unsafe.getInt(data);
256 if (order != MotifDnDConstants.getByteOrderByte()) {
257 return swap(i);
258 } else {
259 return i;
260 }
261 }
262 }
263
264
265
266
267
268
269
270
271
272
273
274 private static long[][] getTargetListTable(long motifWindow)
275 throws XException {
276
277 WindowPropertyGetter wpg = new WindowPropertyGetter(motifWindow,
278 XA_MOTIF_DRAG_TARGETS,
279 0, 100000L,
280 false,
281 XA_MOTIF_DRAG_TARGETS.getAtom());
282 try {
283 int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
284
285 if (status != XConstants.Success
286 || wpg.getActualType() != XA_MOTIF_DRAG_TARGETS.getAtom()
287 || wpg.getData() == 0) {
288
289 return null;
290 }
291
292 long data = wpg.getData();
293
294 if (unsafe.getByte(data + 1) != MOTIF_DND_PROTOCOL_VERSION) {
295 return null;
296 }
297
298 boolean swapNeeded = unsafe.getByte(data + 0) != getByteOrderByte();
299
300 short numTargetLists = unsafe.getShort(data + 2);
301
302 if (swapNeeded) {
303 numTargetLists = Swapper.swap(numTargetLists);
304 }
305
306 long[][] table = new long[numTargetLists][];
307 ByteOrder byteOrder = ByteOrder.nativeOrder();
308 if (swapNeeded) {
309 byteOrder = (byteOrder == ByteOrder.LITTLE_ENDIAN) ?
310 ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
311 }
312
313 long bufptr = data + 8;
314 for (short i = 0; i < numTargetLists; i++) {
315 short numTargets = unsafe.getShort(bufptr);
316 bufptr += 2;
317 if (swapNeeded) {
318 numTargets = Swapper.swap(numTargets);
319 }
320
321 table[i] = new long[numTargets];
322
323 for (short j = 0; j < numTargets; j++) {
324
325
326 int target = 0;
327 if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
328 for (int idx = 0; idx < 4; idx++) {
329 target |= (unsafe.getByte(bufptr + idx) << 8*idx)
330 & (0xFF << 8*idx);
331 }
332 } else {
333 for (int idx = 0; idx < 4; idx++) {
334 target |= (unsafe.getByte(bufptr + idx) << 8*(3-idx))
335 & (0xFF << 8*(3-idx));
336 }
337 }
338
339
340 table[i][j] = target;
341 bufptr += 4;
342 }
343 }
344 return table;
345 } finally {
346 wpg.dispose();
347 }
348 }
349
350 private static void putTargetListTable(long motifWindow, long[][] table)
351 throws XException {
352 assert XToolkit.isAWTLockHeldByCurrentThread();
353
354 int tableSize = 8;
355
356 for (int i = 0; i < table.length; i++) {
357 tableSize += table[i].length * 4 + 2;
358 }
359
360 long data = unsafe.allocateMemory(tableSize);
361
362 try {
363
364 unsafe.putByte(data + 0, getByteOrderByte());
365
366 unsafe.putByte(data + 1, MOTIF_DND_PROTOCOL_VERSION);
367
368 unsafe.putShort(data + 2, (short)table.length);
369
370 unsafe.putInt(data + 4, tableSize);
371
372 long bufptr = data + 8;
373
374 for (int i = 0; i < table.length; i++) {
375 unsafe.putShort(bufptr, (short)table[i].length);
376 bufptr += 2;
377
378 for (int j = 0; j < table[i].length; j++) {
379 int target = (int)table[i][j];
380
381
382 if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
383 for (int idx = 0; idx < 4; idx++) {
384 byte b = (byte)((target & (0xFF << (8*idx))) >> (8*idx));
385 unsafe.putByte(bufptr + idx, b);
386 }
387 } else {
388 for (int idx = 0; idx < 4; idx++) {
389 byte b = (byte)((target & (0xFF << (8*idx))) >> (8*idx));
390 unsafe.putByte(bufptr + (3-idx), b);
391 }
392 }
393 bufptr += 4;
394 }
395 }
396
397 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
398 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
399 motifWindow,
400 XA_MOTIF_DRAG_TARGETS.getAtom(),
401 XA_MOTIF_DRAG_TARGETS.getAtom(), 8,
402 XConstants.PropModeReplace,
403 data, tableSize);
404
405 XToolkit.RESTORE_XERROR_HANDLER();
406
407 if (XToolkit.saved_error != null &&
408 XToolkit.saved_error.get_error_code() != XConstants.Success) {
409
410
411 motifWindow = createMotifWindow();
412
413 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
414 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
415 motifWindow,
416 XA_MOTIF_DRAG_TARGETS.getAtom(),
417 XA_MOTIF_DRAG_TARGETS.getAtom(), 8,
418 XConstants.PropModeReplace,
419 data, tableSize);
420
421 XToolkit.RESTORE_XERROR_HANDLER();
422
423 if (XToolkit.saved_error != null &&
424 XToolkit.saved_error.get_error_code() != XConstants.Success) {
425 throw new XException("Cannot write motif drag targets property.");
426 }
427 }
428 } finally {
429 unsafe.freeMemory(data);
430 }
431 }
432
433 static int getIndexForTargetList(long[] formats) throws XException {
434 assert XToolkit.isAWTLockHeldByCurrentThread();
435
436 if (formats.length > 0) {
437
438 formats = (long[])formats.clone();
439
440 Arrays.sort(formats);
441 }
442
443
444
445
446
447
448
449
450
451 long motifWindow = getMotifWindow();
452
453 XlibWrapper.XGrabServer(XToolkit.getDisplay());
454
455 try {
456 long[][] table = getTargetListTable(motifWindow);
457
458 if (table != null) {
459 for (int i = 0; i < table.length; i++) {
460 boolean equals = true;
461 if (table[i].length == formats.length) {
462 for (int j = 0; j < table[i].length; j++) {
463 if (table[i][j] != formats[j]) {
464 equals = false;
465 break;
466 }
467 }
468 } else {
469 equals = false;
470 }
471
472 if (equals) {
473 XlibWrapper.XUngrabServer(XToolkit.getDisplay());
474 return i;
475 }
476 }
477 } else {
478
479
480
481 table = new long[2][];
482 table[0] = new long[] { 0 };
483 table[1] = new long[] { XAtom.XA_STRING };
484 }
485
486
487 long[][] new_table = new long[table.length + 1][];
488
489
490 for (int i = 0; i < table.length; i++) {
491 new_table[i] = table[i];
492 }
493
494
495 new_table[new_table.length - 1] = formats;
496
497 putTargetListTable(motifWindow, new_table);
498
499 return new_table.length - 1;
500 } finally {
501 XlibWrapper.XUngrabServer(XToolkit.getDisplay());
502 }
503 }
504
505 static long[] getTargetListForIndex(int index) {
506 long motifWindow = getMotifWindow();
507 long[][] table = getTargetListTable(motifWindow);
508
509 if (index < 0 || index >= table.length) {
510 return new long[0];
511 } else {
512 return table[index];
513 }
514 }
515
516 static byte getByteOrderByte() {
517
518 return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ?
519 (byte)0x6C : (byte)0x42;
520 }
521
522 static void writeDragInitiatorInfoStruct(long window, int index) throws XException {
523 assert XToolkit.isAWTLockHeldByCurrentThread();
524
525 long structData = unsafe.allocateMemory(MOTIF_INITIATOR_INFO_SIZE);
526
527 try {
528
529 unsafe.putByte(structData, getByteOrderByte());
530
531 unsafe.putByte(structData + 1, MOTIF_DND_PROTOCOL_VERSION);
532
533 unsafe.putShort(structData + 2, (short)index);
534
535 unsafe.putInt(structData + 4, (int)XA_MOTIF_ATOM_0.getAtom());
536
537 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
538 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
539 XA_MOTIF_ATOM_0.getAtom(),
540 XA_MOTIF_DRAG_INITIATOR_INFO.getAtom(),
541 8, XConstants.PropModeReplace,
542 structData, MOTIF_INITIATOR_INFO_SIZE);
543 XToolkit.RESTORE_XERROR_HANDLER();
544
545 if (XToolkit.saved_error != null &&
546 XToolkit.saved_error.get_error_code() != XConstants.Success) {
547 throw new XException("Cannot write drag initiator info");
548 }
549 } finally {
550 unsafe.freeMemory(structData);
551 }
552 }
553
554 static void writeDragReceiverInfoStruct(long window) throws XException {
555 assert XToolkit.isAWTLockHeldByCurrentThread();
556
557 int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
558 long data = unsafe.allocateMemory(dataSize);
559
560 try {
561 unsafe.putByte(data, MotifDnDConstants.getByteOrderByte());
562 unsafe.putByte(data + 1, MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION);
563 unsafe.putByte(data + 2, (byte)MotifDnDConstants.MOTIF_DYNAMIC_STYLE);
564 unsafe.putByte(data + 3, (byte)0);
565 unsafe.putInt(data + 4, (int)window);
566 unsafe.putShort(data + 8, (short)0);
567 unsafe.putShort(data + 10, (short)0);
568 unsafe.putInt(data + 12, dataSize);
569
570 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
571 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
572 XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
573 XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
574 8, XConstants.PropModeReplace,
575 data, dataSize);
576 XToolkit.RESTORE_XERROR_HANDLER();
577
578 if (XToolkit.saved_error != null &&
579 XToolkit.saved_error.get_error_code() != XConstants.Success) {
580 throw new XException("Cannot write Motif receiver info property");
581 }
582 } finally {
583 unsafe.freeMemory(data);
584 }
585 }
586
587 public static int getMotifActionsForJavaActions(int javaActions) {
588 int motifActions = MOTIF_DND_NOOP;
589
590 if ((javaActions & DnDConstants.ACTION_MOVE) != 0) {
591 motifActions |= MOTIF_DND_MOVE;
592 }
593 if ((javaActions & DnDConstants.ACTION_COPY) != 0) {
594 motifActions |= MOTIF_DND_COPY;
595 }
596 if ((javaActions & DnDConstants.ACTION_LINK) != 0) {
597 motifActions |= MOTIF_DND_LINK;
598 }
599
600 return motifActions;
601 }
602
603 public static int getJavaActionsForMotifActions(int motifActions) {
604 int javaActions = DnDConstants.ACTION_NONE;
605
606 if ((motifActions & MOTIF_DND_MOVE) != 0) {
607 javaActions |= DnDConstants.ACTION_MOVE;
608 }
609 if ((motifActions & MOTIF_DND_COPY) != 0) {
610 javaActions |= DnDConstants.ACTION_COPY;
611 }
612 if ((motifActions & MOTIF_DND_LINK) != 0) {
613 javaActions |= DnDConstants.ACTION_LINK;
614 }
615
616 return javaActions;
617 }
618 }